package com.dhcc.bpm.modules.system.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dhcc.bpm.common.exception.BusinessException;
import com.dhcc.bpm.modules.system.wrapper.MenuWrapper;
import com.dhcc.bpm.modules.system.entity.Menu;
import com.dhcc.bpm.modules.system.entity.RoleMenu;
import com.dhcc.bpm.modules.system.entity.TopMenuSetting;
import com.dhcc.bpm.modules.system.mapper.MenuMapper;
import com.dhcc.bpm.modules.system.service.IRoleMenuService;
import com.dhcc.bpm.modules.system.service.ITopMenuSettingService;
import com.dhcc.bpm.modules.system.dto.MenuDTO;
import com.dhcc.bpm.modules.system.entity.RoleScope;
import com.dhcc.bpm.modules.system.service.IMenuService;
import com.dhcc.bpm.modules.system.service.IRoleScopeService;
import com.dhcc.bpm.modules.system.vo.MenuVO;
import lombok.AllArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.secure.utils.SecureUtil;
import org.springblade.core.tool.constant.BladeConstant;
import org.springblade.core.tool.node.ForestNodeMerger;
import org.springblade.core.tool.support.Kv;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.core.tool.utils.WebUtil;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

import static org.springblade.core.cache.constant.CacheConstant.MENU_CACHE;

/**
 * @ClassName MenuServiceImpl
 * @Description  服务实现类
 * @Author sjm
 * @Date 2020/2/21 0021 15:16
 * @Version V1.0
 * @Copyright: 2020 东华软件 . All rights reserved.
 **/
@Service("blade_menu")
@AllArgsConstructor
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements IMenuService {
    private final static Logger log = LoggerFactory.getLogger(MenuServiceImpl.class);
	private IRoleMenuService roleMenuService;
	private IRoleScopeService roleScopeService;
	private ITopMenuSettingService topMenuSettingService;
	private StringRedisTemplate stringRedisTemplate;

	/**
	 * 自定义分页
	 * @Author sjm
	 * @Date 19:12 2020/2/21 0021
	 * @param page
	 * @param menu
	 * @return com.baomidou.mybatisplus.core.metadata.IPage<com.dhcc.bpm.modules.system.vo.MenuVO>
	 **/
	@Override
	public IPage<MenuVO> selectMenuPage(IPage<MenuVO> page, MenuVO menu) {
		return page.setRecords(baseMapper.selectMenuPage(page, menu));
	}

	/**
	 *  菜单树形结构
	 * @Author sjm
	 * @Date 19:13 2020/2/21 0021
	 * @param roleId
	 * @param topMenuId
	 * @return java.util.List<com.dhcc.bpm.modules.system.vo.MenuVO>
	 **/
	@Override
	public List<MenuVO> routes(String roleId, Long topMenuId) {
		ValueOperations<String, String> opsForValue = stringRedisTemplate.opsForValue();
		//获取token
        String token = WebUtil.getRequest().getHeader("Blade-Auth");
        if(token == null){
            token = WebUtil.getRequest().getParameter("Blade-Auth");
        }
        token = token.replace("bearer ","");
        log.info("流程设计器权限token:{}", token);
		AtomicReference<String> isFlag = new AtomicReference<>("false");
		if (StringUtil.isBlank(roleId)) {
			return null;
		}
		List<Menu> allMenus = baseMapper.allMenu();
//		List<Menu> roleMenus = (SecureUtil.isAdministrator() && Func.isEmpty(topMenuId)) ? allMenus : baseMapper.roleMenu(Func.toLongList(roleId), topMenuId);
		List<Menu> roleMenus = baseMapper.roleMenu(Func.toLongList(roleId), topMenuId);
		if(roleMenus == null || roleMenus.size() < 1){
			roleMenus = allMenus;
		}
		roleMenus.forEach(role -> {
			if (role.getId() == 1206879664765849602L){
				isFlag.set("true");
			}
		});
		BladeUser bladeUser = AuthUtil.getUser();
		//工作流校验用户是否拥有流程设计权限
		opsForValue.set(bladeUser.getAccount() + "@workFlowRole", isFlag.get(), 3600, TimeUnit.SECONDS);
		if(token != null){
			//将账号信息存入token
			opsForValue.set(token, bladeUser.getAccount() + "@workFlowRole", 3600, TimeUnit.SECONDS);
		}
		return buildRoutes(allMenus, roleMenus);
	}

	/**
	 * 菜单树形结构
	 * @Author sjm
	 * @Date 19:13 2020/2/21 0021
	 * @param roleId
     * @param topMenuId
	 * @return java.util.List<com.dhcc.bpm.modules.system.vo.MenuVO>
	 **/
	@Override
	public List<MenuVO> routesExt(String roleId, Long topMenuId) {
		if (StringUtil.isBlank(roleId)) {
			return null;
		}
		List<Menu> allMenus = baseMapper.allMenuExt();
		List<Menu> roleMenus = baseMapper.roleMenuExt(Func.toLongList(roleId), topMenuId);
		return buildRoutes(allMenus, roleMenus);
	}

	private List<MenuVO> buildRoutes(List<Menu> allMenus, List<Menu> roleMenus) {
		List<Menu> routes = new LinkedList<>(roleMenus);
		roleMenus.forEach(roleMenu -> recursion(allMenus, routes, roleMenu));
		routes.sort(Comparator.comparing(Menu::getSort));
		MenuWrapper menuWrapper = new MenuWrapper();
		List<Menu> collect = routes.stream().filter(x -> Func.isEquals(x.getCategory(), 1)).collect(Collectors.toList());
		return menuWrapper.listNodeVO(collect);
	}

	private void recursion(List<Menu> allMenus, List<Menu> routes, Menu roleMenu) {
		Optional<Menu> menu = allMenus.stream().filter(x -> Func.isEquals(x.getId(), roleMenu.getParentId())).findFirst();
		if (menu.isPresent() && !routes.contains(menu.get())) {
			routes.add(menu.get());
			recursion(allMenus, routes, menu.get());
		}
	}

	/**
	 * 按钮树形结构
	 * @Author sjm
	 * @Date 19:13 2020/2/21 0021
	 * @param roleId
	 * @return java.util.List<com.dhcc.bpm.modules.system.vo.MenuVO>
	 **/
	@Override
	public List<MenuVO> buttons(String roleId) {
		List<Menu> buttons = (SecureUtil.isAdministrator()) ? baseMapper.allButtons() : baseMapper.buttons(Func.toLongList(roleId));
		//List<Menu> buttons = baseMapper.buttons(Func.toIntList(roleId));
		MenuWrapper menuWrapper = new MenuWrapper();
		return menuWrapper.listNodeVO(buttons);
//		return buttons;
	}

	/**
	 * 树形结构
	 * @Author sjm
	 * @Date 19:13 2020/2/21 0021
	 * @param
	 * @return java.util.List<com.dhcc.bpm.modules.system.vo.MenuVO>
	 **/
	@Override
	public List<MenuVO> tree() {
		return ForestNodeMerger.merge(baseMapper.tree());
	}

	/**
	 * 授权树形结构
	 * @Author sjm
	 * @Date 19:14 2020/2/21 0021
	 * @param user
	 * @return java.util.List<com.dhcc.bpm.modules.system.vo.MenuVO>
	 **/
	@Override
	public List<MenuVO> grantTree(BladeUser user) {
		return ForestNodeMerger.merge(user.getTenantId().equals(BladeConstant.ADMIN_TENANT_ID) ? baseMapper.grantTree() : baseMapper.grantTreeByRole(Func.toLongList(user.getRoleId())));
	}

	/**
	 * 顶部菜单树形结构
	 * @Author sjm
	 * @Date 19:14 2020/2/21 0021
	 * @param user
	 * @return java.util.List<com.dhcc.bpm.modules.system.vo.MenuVO>
	 **/
	@Override
	public List<MenuVO> grantTopTree(BladeUser user) {
		return ForestNodeMerger.merge(user.getTenantId().equals(BladeConstant.ADMIN_TENANT_ID) ? baseMapper.grantTopTree() : baseMapper.grantTopTreeByRole(Func.toLongList(user.getRoleId())));
	}

	/**
	 * 数据权限授权树形结构
	 * @Author sjm
	 * @Date 19:14 2020/2/21 0021
	 * @param user
	 * @return java.util.List<com.dhcc.bpm.modules.system.vo.MenuVO>
	 **/
	@Override
	public List<MenuVO> grantDataScopeTree(BladeUser user) {
		return ForestNodeMerger.merge(user.getTenantId().equals(BladeConstant.ADMIN_TENANT_ID) ? baseMapper.grantDataScopeTree() : baseMapper.grantDataScopeTreeByRole(Func.toLongList(user.getRoleId())));
	}

	/**
	 * 接口权限授权树形结构
	 * @Author sjm
	 * @Date 19:14 2020/2/21 0021
	 * @param user
	 * @return java.util.List<com.dhcc.bpm.modules.system.vo.MenuVO>
	 **/
	@Override
	public List<MenuVO> grantApiScopeTree(BladeUser user) {
		return ForestNodeMerger.merge(user.getTenantId().equals(BladeConstant.ADMIN_TENANT_ID) ? baseMapper.grantApiScopeTree() : baseMapper.grantApiScopeTreeByRole(Func.toLongList(user.getRoleId())));
	}

	/**
	 * 默认选中节点
	 * @Author sjm
	 * @Date 19:14 2020/2/21 0021
	 * @param roleIds
	 * @return java.util.List<java.lang.String>
	 **/
	@Override
	public Map<String, List<String>> roleTreeKeys(String roleIds) {
		List<RoleMenu> roleMenus = roleMenuService.list(Wrappers.<RoleMenu>query().lambda().in(RoleMenu::getRoleId, Func.toLongList(roleIds)));
		Map<String, List<RoleMenu>> map = roleMenus.stream().collect(Collectors.groupingBy(RoleMenu::getType));
		Map<String, List<String>> menuMap = new HashMap<>();
		//全选的按钮
		List<RoleMenu> allCheck = roleMenus.stream().filter(s -> s.getType().equals("1")).collect(Collectors.toList());
		menuMap.put("checked",allCheck.stream().map(roleMenu -> Func.toStr(roleMenu.getMenuId())).collect(Collectors.toList()));
		//半选的按钮
		List<RoleMenu> helfCheck = roleMenus.stream().filter(s -> s.getType().equals("2")).collect(Collectors.toList());
		menuMap.put("halfChecked",helfCheck.stream().map(roleMenu -> Func.toStr(roleMenu.getMenuId())).collect(Collectors.toList()));
		return menuMap;
	}

	/**
	 * 默认选中节点
	 * @Author sjm
	 * @Date 19:14 2020/2/21 0021
	 * @param topMenuIds
	 * @return java.util.List<java.lang.String>
	 **/
	@Override
	public List<String> topTreeKeys(String topMenuIds) {
		List<TopMenuSetting> settings = topMenuSettingService.list(Wrappers.<TopMenuSetting>query().lambda().in(TopMenuSetting::getTopMenuId, Func.toLongList(topMenuIds)));
		return settings.stream().map(setting -> Func.toStr(setting.getMenuId())).collect(Collectors.toList());
	}

	/**
	 * 默认选中节点
	 * @Author sjm
	 * @Date 19:15 2020/2/21 0021
	 * @param roleIds
	 * @return java.util.List<java.lang.String>
	 **/
	@Override
	public Map<String, List<String>> dataScopeTreeKeys(String roleIds) {
		RoleScope roleScope = new RoleScope();
		roleScope.setScopeCategory(1);
		roleScope.setRoleId(Long.valueOf(roleIds));
		List<RoleScope> list = roleScopeService.list(Wrappers.query(roleScope));
		Map<String, List<String>> dataMap = new HashMap<>();
		//全选的按钮
		List<RoleScope> allCheck = list.stream().filter(s -> s.getType().equals("1")).collect(Collectors.toList());
		dataMap.put("checked",allCheck.stream().map(dataScope -> Func.toStr(dataScope.getScopeId())).collect(Collectors.toList()));
		//半选的按钮
		List<RoleScope> helfCheck = list.stream().filter(s -> s.getType().equals("2")).collect(Collectors.toList());
		dataMap.put("halfChecked",helfCheck.stream().map(dataScope -> Func.toStr(dataScope.getScopeId())).collect(Collectors.toList()));
		return dataMap;
	}

	/**
	 * 默认选中节点
	 * @Author sjm
	 * @Date 19:15 2020/2/21 0021
	 * @param roleIds
	 * @return java.util.List<java.lang.String>
	 **/
	@Override
	public Map<String, List<String>> apiScopeTreeKeys(String roleIds) {
		RoleScope roleScope = new RoleScope();
		roleScope.setScopeCategory(2);
		roleScope.setRoleId(Long.valueOf(roleIds));
		List<RoleScope> list = roleScopeService.list(Wrappers.query(roleScope));
		Map<String, List<String>> apiMap = new HashMap<>();
		//全选的按钮
		List<RoleScope> allCheck = list.stream().filter(s -> s.getType().equals("1")).collect(Collectors.toList());
		apiMap.put("checked",allCheck.stream().map(dataScope -> Func.toStr(dataScope.getScopeId())).collect(Collectors.toList()));
		//半选的按钮
		List<RoleScope> helfCheck = list.stream().filter(s -> s.getType().equals("2")).collect(Collectors.toList());
		apiMap.put("halfChecked",helfCheck.stream().map(dataScope -> Func.toStr(dataScope.getScopeId())).collect(Collectors.toList()));
		return apiMap;
	}

	/**
	 * 获取配置的角色权限
	 * @Author sjm
	 * @Date 19:15 2020/2/21 0021
	 * @param user
	 * @return java.util.List<org.springblade.core.tool.support.Kv>
	 **/
	@Override
	@Cacheable(cacheNames = MENU_CACHE, key = "'auth:routes:' + #user.roleId")
	public List<Kv> authRoutes(BladeUser user) {
		List<MenuDTO> routes = baseMapper.authRoutes(Func.toLongList(user.getRoleId()));
		List<Kv> list = new ArrayList<>();
		routes.forEach(route -> list.add(Kv.create().set(route.getPath(), Kv.create().set("authority", Func.toStrArray(route.getAlias())))));
		return list;
	}

	/**
	 * 删除菜单
	 * @Author sjm
	 * @Date 19:15 2020/2/21 0021
	 * @param ids
	 * @return boolean
	 **/
	@Override
	public boolean removeMenu(String ids) {
		Integer cnt = Math.toIntExact(baseMapper.selectCount(Wrappers.<Menu>query().lambda().in(Menu::getParentId, Func.toLongList(ids))));
		if (cnt > 0) {
			throw new BusinessException("请先删除子节点!");
		}
		return removeByIds(Func.toLongList(ids));
	}

	/**
	 * 提交
	 * @Author sjm
	 * @Date 19:15 2020/2/21 0021
	 * @param menu
	 * @return boolean
	 **/
	@Override
	public boolean submit(Menu menu) {
		menu.setIsDeleted(BladeConstant.DB_NOT_DELETED);
		return saveOrUpdate(menu);
	}
}
